#!/usr/bin/env python

import os

class VimProjectCreator( object ):
	""" Project name - base name for all created files """
	project_name = None

	""" Absolute path of a project sources """
	base_path = None

	""" Paths relative to base_path, where creator will start searching for files """
	paths = []

	""" Files with matching suffixes will be add to project """
	suffixes = []

	""" Should creator include hidden files ( beginning with dot ) """
	include_hidden = False

	""" Ctags program options """
	ctags_options='--c++-kinds=+p --fields=+iaS --extra=+q'

	def __init__( self ):
		self.__lst = {}

	def __add_file( self, filepath ):
		path = os.path.dirname( filepath )
		name = os.path.basename( filepath )

		try:
			self.__lst[ path ].append( ( 'f', name ) )
		except KeyError:
			self.__lst[ path ] = [ ( 'f', name ) ]

	def __add_dir( self, filepath ):
		path = os.path.dirname( filepath )
		name = os.path.basename( filepath )

		try:
			self.__lst[ path ].append( ( 'd', name ) )
		except KeyError:
			self.__lst[ path ] = [ ( 'd', name ) ]

		self.__lst[ filepath ] = []

	def __make_listing( self, cwd ):
		if cwd.endswith( '/.' ):
			cwd = cwd[:-2]

		try:
			prefix, suffix = cwd.split( self.base_path + '/', 1 )
		except ValueError:
			pass
		else:
			self.__add_dir( suffix )

		for entry in sorted( os.listdir( cwd ) ):
			if not self.include_hidden and entry.startswith( '.' ):
				continue

			path = '%s/%s' % ( cwd, entry )

			if os.path.isdir( path ):
				self.__make_listing( path )
			elif os.path.isfile( path ):
				if any( map( lambda s: entry.endswith( s ), self.suffixes ) ):
					try:
						prefix, suffix = path.split( self.base_path + '/', 1 )
					except ValueError:
						print "Oops: %s" % path
					else:
						self.__add_file( suffix )
			else:
				raise SystemExit( 'Unknown file type for: %s!' % path )

	def makeListing( self ):
		for path in self.paths:
			self.__make_listing( '%s/%s' % ( self.base_path, path ) )

	def generateVimProject( self, view = 'flat' ):
		assert view in [ 'flat', 'tree' ]

		prj_file = open( '%s.prj' % self.project_name, 'w' )

		print >>prj_file, 'project_entry ::='
		print >>prj_file, '%s=%s {' % ( self.project_name, os.path.abspath( self.base_path ) )

		if view == 'flat':
			for base in sorted( self.__lst ):
				print >>prj_file, ' %s=%s/%s {' % ( base or '/' , os.path.abspath( self.base_path ), base )

				for ft, file in sorted( self.__lst[ base ] ):
					if ft == 'f':
						print >>prj_file, '  %s' % file

				print >>prj_file, ' }'
		else:
			def recurse( path, indent = 1 ):
				for ft, name in sorted( self.__lst[ path ] ):
					if ft == 'd':
						if len( path ):
							relpath = '%s/%s' % ( path, name )
						else:
							relpath = '%s' % ( name )

						print >>prj_file, '%s%s=%s/%s {' % ( ' ' * indent, name or '/' , os.path.abspath( self.base_path ), relpath )

						recurse( relpath, indent + 1 )

						print >>prj_file, '%s}' % ( ' ' * indent )
					else:
						print >>prj_file, '%s%s' % ( ' ' * indent, name )

			recurse( '' )

		print >>prj_file, '}'

		prj_file.close()

	def generateTags( self ):
		lst_file = open( '%s.lst' % self.project_name, 'w' )

		for base in sorted( self.__lst ):
			if len( base ):
				path = '%s/%s' % ( self.base_path, base )
			else:
				path = self.base_path

			for ft, file in self.__lst[ base ]:
				if ft == 'f':
					print >>lst_file, '%s/%s' % ( path, file )

		lst_file.close()

		os.system( 'ctags %(opts)s -L %(name)s.lst -f %(name)s.tags' % { 'opts': self.ctags_options, 'name': self.project_name } )

if __name__ == '__main__':
	vpc = VimProjectCreator()

	vpc.project_name	= 'YAGE'
	vpc.base_path		= os.path.expanduser( '~/yage-paradigm' )
	vpc.paths			= [ 'src' ]
	vpc.suffixes		= [ '.cc', '.hh', '.c', '.h', '.cpp', '.txt' ]

	vpc.makeListing()
	vpc.generateVimProject( view = 'tree' )
	vpc.generateTags()
